/******************************************************************
			MOLIPC.C
*******************************************************************/

#define _GNU_SOURCE 
#include <stdio.h>
#include <stdint.h> 
#include <dlfcn.h> 
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*---------------------- MINIX HEADERS ---------------------------*/

#include "../include/minix/config.h" 	
#include "../include/minix/endpoint.h" 	
#include "../../kernel/ipc.h"			

/* #include "../../kernel/const.h"  	*/
/* #include "../../kernel/type.h"		*/
/* #include "../../kernel/priv.h"		*/
/* #include "../../kernel/com.h"		*/
/* #include "../../kernel/endpoint.h"	*/

#define MOLDBG 1
#include "../include/mol/molminix.h"
#include "../include/mol/mollib.h"

/********************************************************/
/* 		MOL IPC FUNCTIONS			*/
/* all IPC function passthrough MINIX kernel deamon molkernel	*/
/* que actua como un HUB de comunicaciones		*/
/* Por lo tanto todos los procesos USER, SERVER, TASK son   */
/* clientes UDP del servidor MOLKERNEL			*/
/************************************************************/

/*------------------------------------------------------*/
/*			ipc_send			*/
/* Send a MOL message 			 		*/
/*------------------------------------------------------*/
int ipc_send(ipc_t *ipc)
{
	int bytes;

OLDEBUG("code=%X spid=%d seq=%ld p_nr=%d p_endpoint=%d srcdst=%d\n",
                ipc->molmsg.code,
                ipc->molmsg.spid,
                ipc->molmsg.seq,
                ipc->molmsg.p_nr,
                ipc->molmsg.p_endpoint,
                ipc->molmsg.srcdst);
	
	NO_EINTR(bytes = sendto(ipc->socket,  		/* Socket to send 	 	*/
			&ipc->molmsg,		/* The datagram result to snd */
			sizeof(mol_msg_t), 	/* The datagram length 		*/
			0,              		/* Flags: no options 		*/
			(struct sockaddr *)&ipc->addr,/* Remote  addr 	*/
			ipc->addrlen)); 		/* Remoter address length 	*/
        if( bytes < 0)
          MOLERROR(" bytes = %d\n", bytes);
                              
	return(OK);
}

/*----------------------------------------------------------*/
/*			ipc_rcv 			*/
/* Receive a MOL  message 				*/
/*----------------------------------------------------------*/
int ipc_rcv(ipc_t *ipc)
{
   	unsigned int addr_len;
   	int bytes;

	addr_len = sizeof (struct sockaddr_in);
	NO_EINTR( bytes = recvfrom(ipc->socket,		/* Socket to receive */
			&ipc->molmsg,		/* Receiving buffer */
			sizeof(mol_msg_t),    	/* Max recv buf size */
			0,              		/* Flags: no options */
			(struct sockaddr *)&ipc->addr,  /* Client Addr */
			&addr_len));  		/* Addr len, in & out */

	if( bytes < 0)
   		MOLERROR(" bytes = %d\n", bytes);

OLDEBUG("code=%X spid=%d seq=%ld p_nr=%d p_endpoint=%d srcdst=%d\n",
                ipc->molmsg.code,
                ipc->molmsg.spid,
                ipc->molmsg.seq,
                ipc->molmsg.p_nr,
                ipc->molmsg.p_endpoint,
                ipc->molmsg.srcdst);
      
	return(OK);
}

/*----------------------------------------------------------*/
/*			ipc_close				*/
/* Close IPC						*/
/*----------------------------------------------------------*/
int ipc_close(mol_proc_t *mpp)
{
	int rcode;
OLDEBUG("\n");
	rcode = close(mpp->ripc.socket);
	if( rcode != 0)
		MOLERROR("close %d\n",rcode);
	rcode = close(mpp->kipc.socket);
	if( rcode != 0)
		MOLERROR("close %d\n",rcode);
return(OK);
}

/*----------------------------------------------------------*/
/*		ipc_open	  	     					*/
/* Open IPC: CONTROL and IPC Channels				*/
/*----------------------------------------------------------*/
int ipc_open(mol_proc_t *mpp)
{
OLDEBUG("\n");

    	/* Creates a UDP socket for the CONTROL Channel		*/
    	mpp->kipc.socket = socket(AF_INET,SOCK_DGRAM,0);
    	if ( mpp->kipc.socket == -1 )
		MOLERROR(" socket error = %d\n", mpp->kipc.socket);

    	/* Creates a UDP socket for the IPC Channel		*/
	mpp->sipc.socket = mpp->ripc.socket = socket(AF_INET,SOCK_DGRAM,0);
    	if ( mpp->ripc.socket == -1 )
		MOLERROR(" socket error = %d\n", mpp->ripc.socket);
 
    	/* set socket address, to use to contact the server */
    	memset(&mpp->kipc.addr,0,sizeof(mpp->kipc.addr));	/* Control IPC struct	*/
    	memset(&mpp->ripc.addr,0,sizeof(mpp->ripc.addr));	/* receive IPC struct	*/
    	memset(&mpp->sipc.addr,0,sizeof(mpp->sipc.addr));	/* send IPC struct	*/
    	mpp->kipc.addr.sin_family = mpp->sipc.addr.sin_family = mpp->ripc.addr.sin_family = AF_INET;


    	mpp->kipc.addr.sin_port   = htons(MOLKERNEL_PORT);
    	mpp->sipc.addr.sin_port   = mpp->ripc.addr.sin_port   = htons(MOLKERNEL_PORT+1);
		
    	mpp->kipc.addr.sin_addr.s_addr	= 
	mpp->sipc.addr.sin_addr.s_addr 	= 
	mpp->ripc.addr.sin_addr.s_addr	= inet_addr(MOLKERNEL_ADDR);

	if ( mpp->ripc.addr.sin_addr.s_addr == INADDR_NONE )
		MOLERROR("bad address: %d\n", INADDR_NONE);

    	mpp->kipc.addrlen = mpp->sipc.addrlen = mpp->ripc.addrlen = sizeof(mpp->ripc.addr);
	return(OK);
}


/*----------------------------------------------------------*/
/*			data_rcv 			*/
/* Receive data copyin or copyout		*/
/*----------------------------------------------------------*/
int data_rcv(ipc_t *ipc, char *bufptr, int nbytes)
{
   	unsigned int addr_len;
   	int bytes;

	addr_len = sizeof (struct sockaddr_in);
	NO_EINTR( bytes = recvfrom(ipc->socket,		/* Socket to receive */
			bufptr,								/* Receiving buffer */
			nbytes,    							/* Max recv buf size */
			0,              					/* Flags: no options */
			(struct sockaddr *)&ipc->addr,  	/* Client Addr */
			&addr_len));  						/* Addr len, in & out */

	if( bytes < 0)
   		MOLERROR(" bytes = %d\n", bytes);

OLDEBUG("DATA: bytes=%d data:%s\n", bytes, bufptr);
      
	return(OK);
}

/*----------------------------------------------------------*/
/*			data_send    			*/
/* Send data copyin or copyout			*/
/*----------------------------------------------------------*/
int data_send(ipc_t *ipc, char *bufptr, int nbytes)
{
   	unsigned int addr_len;
   	int bytes;

	addr_len = sizeof (struct sockaddr_in);
	NO_EINTR(bytes = sendto(ipc->socket,  		/* Socket to send 	 	*/
			bufptr,								/* The datagram result to snd */
			nbytes, 							/* The datagram length 		*/
			0,              					/* Flags: no options 		*/
			(struct sockaddr *)&ipc->addr,		/* Remote  addr 	*/
			ipc->addrlen)); 					/* Remoter address length 	*/
			
	if( bytes < 0)
   		MOLERROR(" bytes = %d\n", bytes);

OLDEBUG("DATA: bytes=%d data:%s\n", bytes, bufptr);
      
	return(OK);
}